#! /usr/bin/env python3

# Create By GF 2023-07-11 20:45

# Py3_Demo_集合(Set)_Explain_GF_2023-07-11.py

# ----------------------------------------------------------------------------------------------------
# 0.1 什么是 Python 集合 (set)。

# 集合 (set) 是由一个或数个形态各异的大小整体组成的，构成集合的事物或对象称作元素或是成员。

# 基本功能是进行成员关系测试和删除重复元素。Python中的集合跟数学上的集合是一致的，不允许有重复元素，而且可以进行交集、并集、差集等运算。

# ----------------------------------------------------------------------------------------------------
# 0.2 Python 集合 (set) 简述。

# 可以使用大括号 { } 或者 set() 函数创建集合，注意：创建一个空集合必须用 set() 而不是 { }，因为 { } 是用来创建一个空字典。

# 集合和列表非常相似 。不同点：

    # 集合中只能存储不可变对象
    
    # 集合中存储的对象是无序（不是按照元素的插入顺序保存）
    
    # 集合中不能出现重复的元素

# ----------------------------------------------------------------------------------------------------
# 1. 创建集合。

# 使用 {} 来创建集合：

s = {1, 2, 3, 3, 3, 2}

# Output:

#>>> s
#{1, 2, 3}

# ------------------------------

s = {'a' , 'b' , 1 , 2 , 3 , 1}

# Output:

#>>> s
#{1, 2, 3, 'a', 'b'}

#>>> s = {[1,2,3],[4,6,7]}
#Traceback (most recent call last):
#  File "<pyshell#5>", line 1, in <module>
#    s = {[1,2,3],[4,6,7]}
#TypeError: unhashable type: 'list'

# ------------------------------

# 使用构造器 set() 创建集合：

# 空集合。
s = set()

# Output:

#>>> s
#set()

# ------------------------------

# 可以通过 set() 来将序列和字典转换为集合：

s = set(range(1, 10))

s = set((1, 2, 3, 3, 2, 1))

s = set([1,2,3,4,5,1,1,2,3,4,5])

s = set('hello')

# ------------------------------

# 使用 set() 将字典转换为集合时，只会包含字典中的键。
s = set({'a':1,'b':2,'c':3})

print(s, type(s))

# Output:

#>>> print(s, type(s))
#{'a', 'b', 'c'} <class 'set'>

# ------------------------------

# 创建集合的推导式语法 (推导式也可以用于推导集合)。
s = {i**2 for i in range(1,4)}

# Output:

#>>> s
#{1, 4, 9}

s = {num for num in range(1, 100) if num % 3 == 0 or num % 5 == 0}

# Output:

#>>> s
#{3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30, 33, 35, 36, 39, 40, 42, 45, 48, 50, 51, 54, 55, 57, 60, 63, 65, 66, 69, 70, 72, 75, 78, 80, 81, 84, 85, 87, 90, 93, 95, 96, 99}

# ------------------------------

# 输出集合，重复的元素被自动去掉：

sites = {'Google', 'Taobao', 'Runoob', 'Facebook', 'Zhihu', 'Baidu'}

print(sites)

# Output:

#>>> print(sites)
#{'Baidu', 'Zhihu', 'Taobao', 'Facebook', 'Google', 'Runoob'}

# 定义集合时的每个元素必须是不可变对象，如列表作为元素时会报错：

#>>> {[1,2], 2}
#TypeError: unhashable type: 'list'

# ----------------------------------------------------------------------------------------------------
# 2. 集合的 CURD (add / update)。

# add() 向集合中添加元素：

s = {'a', 'b', 'c'}

s.add(2)

# Output:

#>>> s
#{2, 'a', 'b', 'c'}

# ------------------------------

# update() 将一个集合中的元素添加到当前集合中：

s.update([1,3,4])

# Output:

#>>> s
#{1, 2, 3, 'a', 4, 'b', 'c'}

# ------------------------------

# update() 可以传递序列或字典作为参数，字典只会使用键：

s2 = set('hello')

s.update(s2)

s.update((10,20,30,40,50))

s.update({10:'ab',20:'bc',100:'cd',1000:'ef'})

# Output:

#>>> s
#{1, 2, 3, 4, 10, 'b', 'e', 20, 'l', 30, 'c', 'o', 'a', 100, 40, 1000, 50, 'h'}

# ----------------------------------------------------------------------------------------------------
# 3. 集合的 CURD (访问)。
    
s = {'a', 'b', 'c'}

# ------------------------------

for i in s:
    print(i)

# Output:

#>>> for i in s:
#    print(i)
# 
#a
#b
#c

# ----------------------------------------------------------------------------------------------------
# 4. 集合的 CURD (删除)。

s = {1, 2, 3, 100, 40, 'o', 10, 1000, 'a', 'h', 'b', 'l', 20, 50, 'e', 30}

# ------------------------------

# pop() 随机删除并返回一个集合中的元素：

result = s.pop()

# Output:

#>>> result = s.pop()
#>>> result
#1

# ------------------------------

# 删除集合中的指定元素：

s = {'b', 'c'}

# 删除不存在的会报错。
s.remove('a')

# Output:

#>>> s.remove('a')
#Traceback (most recent call last):
#  File "<pyshell#57>", line 1, in <module>
#    s.remove('a')
#KeyError: 'a'

# ------------------------------

# 删除一个元素，无则忽略不报错。
s.discard('3')

# Output:

#>>> s
#{'b', 'c'}
#>>> s.discard('3')
#>>> s
#{'b', 'c'}

# ------------------------------

# clear() 清空集合。
s.clear()

# Output:

#>>> s
#{'b', 'c'}
#>>> s.clear()
#>>> s
#set()

# ----------------------------------------------------------------------------------------------------
# 5. Python 集合 - 其它。

# 支持关于容器类型的一些通用操作：

s = {'a', 'b', 'c'}

# ------------------------------

# 3 长度。
len(s)

# ------------------------------

# 'c' 最大值。
max(s)

# ------------------------------

# 'a' 最小值。
min(s)

# ------------------------------

# True 是否有一真。
any(s)

# ------------------------------

# True 是否全真。
all(s)

# ------------------------------

# 返回排序后的列表。
sorted(s)

# Output:

#>>> s = ['a', 'b', 'c']
#>>> sorted(s)
#['a', 'b', 'c']

# ------------------------------

# pop() 原本是删除最后一个元素，但在集合中因为元素无序所以随机。
s.pop()

# ------------------------------

# 深拷贝, s 变化不影响 s2。
s2 = s.copy()


# ----------------------------------------------------------------------------------------------------
# 6. Python 集合 - 运算操作。

# 判断是否有某个元素：

# 使用 in 和 not in 来检查集合中的元素。

s = {'a', 'b', 'c'}

# ------------------------------

'a' in s

# Output:

#>>> 'a' in s
#True

# ------------------------------

print('c' not in s)

# Output:

#>>> print('c' not in s)
#False

# ------------------------------

# 集合的运算：

# 在对集合做运算时，不会影响原来的集合，而是返回一个运算结果。

s1 = {1,2,3}

s2 = {2,3,4}

# ------------------------------

# & 求交集。
s1 & s2

# Output:

#>>> s1 & s2
#{2, 3}

# ------------------------------

# intersection() 求交集。
s1.intersection(s2)

# Output:

#>>> s1.intersection(s2)
#{2, 3}

# ------------------------------

# intersection() 求交集，并覆盖 s1。
s1.intersection_update(s2)

# ------------------------------

# | 求并集。
s1 | s2  # {1, 2, 3, 4} 并集

# Output:

#>>> s1 | s2
#{1, 2, 3, 4}

# ------------------------------

# union() 求并集。
s1.union(s2) # {1, 2, 3, 4} 并集

# Output:

#>>> s1.union(s2)
#{1, 2, 3, 4}

# ------------------------------

# difference() 求差集。
s1.difference(s2)

# Output:

#>>> s1.difference(s2)
#{1}

# ------------------------------

# difference() 求差集，并覆盖 s1。
s1.difference_update(s2)

# ------------------------------

# symmetric_difference() 交集之外。
s1.symmetric_difference(s2)

# Output:

#>>> s1.symmetric_difference(s2)
#{1, 4}

# ------------------------------

# 判断是否没有交集。
s1.isdisjoint(s2)

# ------------------------------

# 判断 s2 是否是 s1 的子集。
s1.issubset(s2) 

# ------------------------------

# 判断s1 是否 s2 的超集, 即 s1 是否包含 s2 的所有元素。
s1.issuperset(s2)

# ----------------------------------------------------------------------------------------------------
# 7. Python 集合 - 冻结的集合 frozenset。

# frozenset() 返回一个冻结的集合，冻结后集合不能再添加或删除任何元素。

frozenset('abc')

# Output:

#>>> frozenset('abc')
#frozenset({'a', 'b', 'c'})

# ------------------------------

frozenset([1,2,3])

# Output:

#>>> frozenset([1,2,3])
#frozenset({1, 2, 3})

# ------------------------------

frozenset({'a':1, 'b':2})

# Output:

#>>> frozenset({'a':1, 'b':2})
#frozenset({'a', 'b'})

# ------------------------------

frozenset(range(3))

# Output:

#>>> frozenset(range(3))
#frozenset({0, 1, 2})

# ------------------------------

frozenset()

# Output:

#>>> frozenset()
#frozenset()

# ------------------------------

# 语法功能：

    # 此函数的语法为 class frozenset([iterable])，其中参数 iterable 是可选的，不传入时会创建一个空的冻结集合，传入时由 iterable 中的元素初始化。
    
    # 参数：
    
        # 参数 iterable 是一个可迭代对象（比如列表、字典、元组、字符串等），将此对象转为一个冻结集合。如果不传则为一个空的冻结集合。
    
    # 特性：
    
        # 冻结集合只是 Python 集合（set）对象的一个不可变版本。set 可以随时修改集合的元素，但冻结集合的元素在创建后保持不变。因此，冻结集可以用作字典中的键或另一个集合的元素。和集合一样，它不是有序的（元素不可以索引）。
    
    # 作用：
    
        # 为什么需要冻结的集合（即不可变的集合）呢？因为在集合的关系中，有集合的中的元素是另一个集合的情况，但是普通集合（set）本身是可变的，那么它的实例就不能放在另一个集合中（set中的元素必须是不可变类型）。
    
        # 所以，frozenset提供了不可变的集合的功能，当集合不可变时，它就满足了作为集合中的元素的要求，就可以放在另一个集合中了。

# ------------------------------

# 操作：

# 冻结集合为一个不可变、无序对象，不对对其进行增加、修改、排序、下标切取等操作，但它也具有集合的一些特性，可以操作交差并补等集合的操作。

fs = frozenset([1,2,3])

# Output:

#>>> fs
#frozenset({1, 2, 3})

# ------------------------------

# 求交集。
fs.intersection([2,3,4])

# Output:

#>>> fs.intersection([2,3,4])
#frozenset({2, 3})

# ------------------------------

# 求差集（对称差）。
fs.symmetric_difference([1,2])

# Output:

#>>> fs.symmetric_difference([1,2])
#frozenset({3})

# ------------------------------

# 求并集。
fs.union([2,3,4])

# Output:

#>>> fs.union([2,3,4])
#frozenset({1, 2, 3, 4})

# ------------------------------

# 判断是否空交集为空。
fs.isdisjoint([2,3,4])

# Output:

#>>> fs.isdisjoint([2,3,4])
#False

# ------------------------------

# 判断是否子集。
fs.issubset([1,2,3,4])

# Output:

#>>> fs.issubset([1,2,3,4])
#True

# ------------------------------

# 判断是否超集。
fs.issuperset([1,2]) # 是否超集

# Output:

#>>> fs.issuperset([1,2])
#True

# ------------------------------

# 浅拷贝。
fs.copy() is fs

# Output:

#>>> fs.copy() is fs
#True

# ----------------------------------------------------------------------------------------------------
# EOF
